上一篇我們介紹milddleware的概念,因為篇幅實在很長,還沒有講到實際上如何把它運用到我們的store裡面,現在讓我們簡單的來把logger加入到store中!
首先,先把昨天的logger加入到 index.js :
const logger = store => next => action => {
console.log('dispatching', action);
let result = next(action);
console.log('next state', store.getState());
return result;
};
再使用applyMiddleware
,把自製的middlewares加入createStore:
import { createStore, applyMiddleware } from 'redux';
import todoApp from './reducers';
let store = createStore(
todoApp,
// applyMiddleware() 告訴 createStore() 如何處理 middleware
applyMiddleware(logger)
);
完整的 index.js ,如下:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import todoApp from './reducers';
import TodoAppContainer from './containers/TodoAppContainer';
const logger = store => next => action => {
console.log('dispatching', action);
let result = next(action);
console.log('next state', store.getState());
return result;
};
let store = createStore(
todoApp,
applyMiddleware(logger)
);
ReactDOM.render(
<Provider store={store}>
<TodoAppContainer />
</Provider>,
document.getElementById('main')
);
現在只要我們有發送任何的action,都可以在console中看到action和next state,自製logger middleware就已經完成囉!不過,其實我們可以用另一套已經寫好的Logger for Redux來達成這個功能。
首先也是透過npm來安裝:
npm install redux-logger --save
透過createLogger
,建立redux-logger的middleware函式:
createLogger(options?: Object) => LoggerMiddleware
裡面可以建立一些options,options不是必填,但可以讓你客製化logger的形式,以下列出options及說明:
{
level = 'log': 'log' | 'console' | 'warn' | 'error' | 'info', // console's level
duration = false: Boolean, // 顯示action執行的時間
timestamp = true: Boolean, // 顯示每個action timestamp
colors: ColorsObject, // 設定console顏色配置
logger = console: LoggerObject, // 自己定義log方法
logErrors = true: Boolean, // 遇到錯誤會丟出錯誤訊息
collapsed, // 是否把console訊息折疊,可是boolean或是一個傳回boolean的函式,函式可以接收getState和action兩個參數
predicate, // 判斷是否記錄log
stateTransformer, // 轉換state格式,例如使用Immutable object轉換成JSON
actionTransformer, // 轉換action格式,例如使用Immutable object轉換成JSON
errorTransformer, // 轉換error格式,例如object變成字串
titleFormatter, // 轉換title格式,預設格式:action @ ${time} ${action.type} (in ${took.toFixed(2)} ms)
diff = false: Boolean, // 顯示state有被改變的地方,diff出來改變的部分
diffPredicate // 過濾要顯示diff的函式
}
把redux-logger加入store的方法,很簡單:
const logger = createLogger();
let store = createStore(
todoApp,
applyMiddleware(logger)
);
有一個地方需要特別注意的,當applyMiddleware
傳入多個middlewares時,logger必須放在最後一個,這表示在dispatch後會先做log,而不會受到其他middleware影響。
Logger must be the last middleware in chain, otherwise it will log thunk and promise, not actual actions.
以下先假設加入另外兩個middleware,redux-thunk、redux-promise當作多個middleware範例:
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import promise from 'redux-promise';
import createLogger from 'redux-logger';
const logger = createLogger();
const store = createStore(
reducer,
applyMiddleware(thunk, promise, logger)
);
當你透過 npm run dev 的時候,可以在console清楚地看到actions的動作都被記錄下來,可以透過比對prev state、next state和action內容來檢查,當程式有error時,很容易可以找出到底是哪邊的問題。
通常我們只會在開發環境時才有log顯示,不讓資訊直接出現在console中,所以我們會在建立store的時候判斷現在的環境:
const middlewares = [];
// 用process.env.NODE_ENV來判斷
if (process.env.NODE_ENV === 'development') {
// options設定執行時間
const logger = createLogger({ duration:true });
middlewares.push(logger);
}
let store = createStore(
todoApp,
applyMiddleware(...middlewares)
);
但是process.env.NODE_ENV
是怎麼產生的呢?還記得我們Day10有提到的webpack plugins,裡面有一個 DefinePlugin 可以讓我們設定變數傳入嗎?
所以我們要在 webpack.config.js 裡面做設定,先不直接export webpack物件,改用一個變數webpackConfig把設定存起來,然後,用node的變數來判斷環境,依照不同環境指定變數:
// 這邊的process.env.NODE_ENV,是node.js的變數
if (process.env.NODE_ENV === 'production') {
// 用DefinePlugin傳入process.env.NODE_ENV變數為production
webpackConfig.plugins.push(
new webpack.DefinePlugin({
'process.env': { 'NODE_ENV': '"production"'}
})
);
} else {
// 用DefinePlugin傳入process.env.NODE_ENV變數為development
webpackConfig.plugins.push(
new webpack.DefinePlugin({
'process.env': { 'NODE_ENV': '"development"'}
})
);
}
最後,我們在 package.json 的script中指定process.env.NODE_ENV
變數,只需指定NODE_ENV:
"scripts": {
"dev": "NODE_ENV=development node server.js",
"prod": "NODE_ENV=production webpack --progress --color",
"test": "echo \"Error: no test specified\" && exit 1"
}
如果是windows的環境需要加上set:
"scripts": {
"dev": "set NODE_ENV=development node server.js",
"prod": "set NODE_ENV=production webpack --progress --color",
"test": "echo \"Error: no test specified\" && exit 1"
}
但如果是多人一起開發,可以使用cross-env的方式來跨平台的問題,當然使用vagrant一起開發就沒這個問題了!這邊提供練習時作參考。
今天的檔案已經放在Git 上,當執行開發環境時,會在console上看到log記錄囉!